﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SmoothStreaming.PerformanceTesting.WinUI
{
    public partial class TestViewControl : UserControl
    {
        public TestViewControl()
        {
            InitializeComponent();
            this.lvChunkResults.ListViewItemSorter = _lvcs;
            this.lvChunkResults.ColumnClick += new ColumnClickEventHandler(OnListViewColumnClicked);
        }

        SmoothStreamPerformanceTest _test = null;
        Dictionary<string, int> _ratingCounters = new Dictionary<string, int>();
        ListViewColumnSorter _lvcs = new ListViewColumnSorter();

        public SmoothStreamPerformanceTest PerformanceTest { get { return _test; } }

        public void StartManifestTest(Uri manifestUri)
        {
            _test = new SmoothStreamPerformanceTest(manifestUri);
            _test.PerformanceTestUpdated += new PerformanceTestUpdateInfoEvent(OnPerformanceTestUpdated);
            _test.ChunkTested += new ChunkTestedEvent(OnChunkTested);

            _test.StartAsync();
            this.lvChunkResults.ListViewItemSorter = _lvcs;
        }


        private void OnListViewColumnClicked(object sender, ColumnClickEventArgs e)
        {
            // Determine if clicked column is already the column that is being sorted.
            if (e.Column == _lvcs.SortColumn)
            {
                // Reverse the current sort direction for this column.
                if (_lvcs.Order == System.Windows.Forms.SortOrder.Ascending)
                {
                    _lvcs.Order = System.Windows.Forms.SortOrder.Descending;
                }
                else
                {
                    _lvcs.Order = System.Windows.Forms.SortOrder.Ascending;
                }
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                _lvcs.SortColumn = e.Column;
                _lvcs.Order = System.Windows.Forms.SortOrder.Ascending;
            }

            // Perform the sort with these new sort options.
            lvChunkResults.Sort();
        }


        void OnChunkTested(SmoothStreamPerformanceTest test, SmoothStreamChunk chunk, ChunkResponse chunkResponse)
        {
            if (this.lvChunkResults.InvokeRequired)
            {
                this.Invoke(new Action<SmoothStreamPerformanceTest, SmoothStreamChunk, ChunkResponse>(OnChunkTested), new object[] { test, chunk, chunkResponse });
                return;
            }
            
            this.lvChunkResults.Items.Insert(0, new ChunkTestListViewItem(chunk, chunkResponse));
            var rating = new ChunkResponseAnalyzer().RateChunkResponse(chunk, chunkResponse);

            string ratingText = rating.ToString();

            if (!_ratingCounters.ContainsKey(ratingText))
            {
                _ratingCounters[ratingText] = 0;
            }

            _ratingCounters[ratingText] += 1;

            RefreshOverallStats();
        }

        private void RefreshOverallStats()
        {
            pbProgress.Maximum = _test.TotalChunks;
            pbProgress.Value = _test.ChunksTested;

            this.txtStats.Text = GenerateStats();
        }

        void OnPerformanceTestUpdated(SmoothStreamPerformanceTest test, string message)
        {
            if (this.txtLog.InvokeRequired)
            {
                this.Invoke(new Action<SmoothStreamPerformanceTest, string>(OnPerformanceTestUpdated), new object[] { test, message });
                return;
            }

            this.txtLog.Text += Environment.NewLine + message;
            this.txtLog.Select(this.txtLog.Text.Length, 0);
            this.txtLog.ScrollToCaret();
        }

        private string GenerateStats()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("Total Chunks: " + _test.TotalChunks.ToString());
            sb.AppendLine("Chunks Tested: " + _test.ChunksTested.ToString());
            sb.AppendLine("Manifest Download Time: " + (_test.ManifestDownloadTime.HasValue ? System.Math.Round(_test.ManifestDownloadTime.Value.TotalMilliseconds, 0) + "ms" : "unknown"));
            sb.AppendLine("Avg Video Chunk Response Time: " + System.Math.Round(_test.AverageVideoResponseTime.TotalMilliseconds, 1) + "ms");
            sb.AppendLine("Avg Audio Chunk Response Time: " + System.Math.Round(_test.AverageAudioResponseTime.TotalMilliseconds, 1) + "ms");
            sb.AppendLine(string.Empty);

            foreach (var rating in _ratingCounters.Keys)
            {
                sb.AppendLine(rating + " Chunks: " + _ratingCounters[rating].ToString() + " (" + 
                    System.Math.Round((Convert.ToDouble(_ratingCounters[rating]) / Convert.ToDouble(_ratingCounters.Sum(rc => rc.Value)) * 100), 2).ToString() + "%)");
            }

            sb.AppendLine(string.Empty);
            int streamCount = 0;
            foreach (var s in _test.StreamIndexes)
            {
                sb.AppendLine("Stream " + streamCount.ToString() + ": " + s.StreamType + ", " + string.Join(", ", s.Bitrates.Select(br => (br / 1000) + "kbps").ToArray()));
                streamCount += 1;
            }

            return sb.ToString();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            _test.Stop();
            this.btnStop.Enabled = false;
        }
    }
}
